package com.piggy.logi.sys.api.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.piggy.common.core.exception.ServiceException;
import com.piggy.common.core.utils.map.GaoDeMapUtil;
import com.piggy.logi.sys.api.bo.*;
import com.piggy.logi.sys.api.domain.LogiSysDept;
import com.piggy.logi.sys.api.service.ZhongYouApiService;
import com.piggy.logi.sys.api.vo.LogiSysDeptExtVo;
import com.piggy.logi.sys.api.vo.TransComVo;
import com.piggy.logi.sys.domain.*;
import com.piggy.logi.sys.enums.FeeTypeEnum;
import com.piggy.logi.sys.enums.GoodOrderStatusEnum;
import com.piggy.logi.sys.service.*;
import com.piggy.sys.api.RemoteSmsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 众油平台可调用API service实现层
 *
 * @author fengxy
 * @date 2024/01/15 15:33
 **/
@Slf4j
@Service
public class ZhongYouApiServiceImpl implements ZhongYouApiService {

    @Resource
    private ILogiSysDeptService deptService;

    @Resource
    private ILogiSysDeptExtService deptExtService;

    @Resource
    private ILogiDeptLineService deptLineService;

    @Resource
    private ILogiCustomerService customerService;

    @Resource
    private ILogiGoodOrderService goodOrderService;

    @Resource
    private ILogiOrderGoodSourceService orderGoodSourceService;

    @Resource
    private ILogiGoodSourceService goodSourceService;

    @Resource
    private ILogiPricePlanService pricePlanService;

    @Resource
    private ILogiPriceSegService priceSegService;

    @Resource
    private ILogiWaybillService waybillService;

    @Resource
    private ILogiScheduleService scheduleService;

    @Resource
    private RemoteSmsService smsService;

    @Override
    public List<TransComVo> getTransComList(TransComQueryBo bo) {
        // 查询条件
        LambdaQueryWrapper<LogiDeptLine> queryWrapper = Wrappers.lambdaQuery(LogiDeptLine.class);
        // 发货地查询
        if (StrUtil.isNotBlank(bo.getDepartDistrict())) {
            queryWrapper.and(a -> a.eq(LogiDeptLine::getDepartDistrict, bo.getDepartDistrict())
                    .or(b -> b.eq(LogiDeptLine::getDepartCity, bo.getDepartCity()).in(LogiDeptLine::getDepartDistrict, 0, null))
                    .or(c -> c.eq(LogiDeptLine::getDepartProvince, bo.getDepartProvince()).in(LogiDeptLine::getDepartCity, 0, null).in(LogiDeptLine::getDepartDistrict, 0, null)));
        } else if (StrUtil.isNotBlank(bo.getDepartCity())) {
            queryWrapper.and(a -> a.eq(LogiDeptLine::getDepartCity, bo.getDepartCity())
                    .or(b -> b.eq(LogiDeptLine::getDepartProvince, bo.getDepartProvince()).in(LogiDeptLine::getDepartCity, 0, null).in(LogiDeptLine::getDepartDistrict, 0, null)));
        } else {
            queryWrapper.eq(LogiDeptLine::getDepartProvince, bo.getDepartProvince());
        }
        // 收货地查询
        if (StrUtil.isNotBlank(bo.getArriveDistrict())) {
            queryWrapper.and(a -> a.eq(LogiDeptLine::getArriveDistrict, bo.getArriveDistrict())
                    .or(b -> b.eq(LogiDeptLine::getArriveCity, bo.getArriveCity()).in(LogiDeptLine::getArriveDistrict, 0, null))
                    .or(c -> c.eq(LogiDeptLine::getArriveProvince, bo.getArriveProvince()).in(LogiDeptLine::getArriveCity, 0, null).in(LogiDeptLine::getArriveDistrict, 0, null)));
        } else if (StrUtil.isNotBlank(bo.getArriveCity())) {
            queryWrapper.and(a -> a.eq(LogiDeptLine::getArriveCity, bo.getArriveCity())
                    .or(b -> b.eq(LogiDeptLine::getArriveProvince, bo.getArriveProvince()).in(LogiDeptLine::getArriveCity, 0, null).in(LogiDeptLine::getArriveDistrict, 0, null)));
        } else {
            queryWrapper.eq(LogiDeptLine::getArriveProvince, bo.getArriveProvince());
        }
        // 查询结果
        List<LogiDeptLine> logiDeptLineList = deptLineService.list(queryWrapper);
        if (CollUtil.isNotEmpty(logiDeptLineList)) {
            List<Long> deptIds = logiDeptLineList.stream().map(LogiDeptLine::getMainDeptId).distinct().collect(Collectors.toList());
            return deptService.list(Wrappers.lambdaQuery(LogiSysDept.class)
                    .eq(LogiSysDept::getStatus, 0)
                    .in(LogiSysDept::getDeptId, deptIds)).stream().map(a -> {
                TransComVo transComVo = new TransComVo();
                transComVo.setDeptId(a.getDeptId());
                transComVo.setDeptName(a.getDeptName());
                transComVo.setPhone(a.getPhone());
                // 获取承运货物
                LogiSysDeptExtVo logiSysDeptExtVo = deptExtService.queryByDeptId(a.getDeptId());
                if (ObjectUtil.isNotNull(logiSysDeptExtVo)) {
                    transComVo.setCarryingGoods(logiSysDeptExtVo.getCarryingGoods());
                }
                return transComVo;
            }).collect(Collectors.toList());
        }
        return CollUtil.newArrayList();
    }

    @Override
    public BigDecimal tryService(TryServiceBo bo) {
        // 查询价格方案
        LogiPricePlan pricePlan = pricePlanService.getOne(Wrappers.lambdaQuery(LogiPricePlan.class)
                .eq(LogiPricePlan::getProjectId, 0)
                .eq(LogiPricePlan::getProjectShiplineId, 0)
                .eq(LogiPricePlan::getDeptId, bo.getDeptId())
                .eq(LogiPricePlan::getFeeMode, FeeTypeEnum.WEIGHTMULTIMILEAGE.getType())
                .last("limit 1"));
        if (ObjectUtil.isNull(pricePlan)) {
            throw new ServiceException("未配置【重量*里程】价格方案");
        }
        // 根据收发货地获取里程数
        BigDecimal miles = getMilesByAddress(bo.getOriginAddress(), bo.getDestinationAddress());
        // 预算运费
        return priceSegService.calcWeigthMultiMileFee(pricePlan.getId(), bo.getWeight(), miles);
    }

    @Override
    public void addOrder(AddOrderBo bo) {
        // 校验提货单号是否已生成过订单
        long count = goodOrderService.count(Wrappers.lambdaQuery(LogiGoodOrder.class)
                .eq(LogiGoodOrder::getPickupOrderNo, bo.getPickupOrderNo())
                .eq(LogiGoodOrder::getParentId, 0)
                .eq(LogiGoodOrder::getGoodOrderType, 1));
        if (count > 0) {
            throw new ServiceException("该提货单号不允许重复生成订单");
        }
        // 创建订单信息
        LogiGoodOrder goodOrder = new LogiGoodOrder();
        goodOrder.setStatus(GoodOrderStatusEnum.NORMAL.getCode());
        goodOrder.setGoodOrderType(1);
        goodOrder.setOwnerOutCode(bo.getOwnerOutCode());
        goodOrder.setPickupOrderNo(bo.getPickupOrderNo());
        goodOrder.setPickupTime(bo.getPickupTime());
        goodOrder.setShipNetId(Math.toIntExact(bo.getDeptId()));
        // 发货方和收货方为同一客户
        LogiCustomer customer = getCustomer(bo.getDeptId(), bo.getCustomerName(), bo.getCustomerCode());
        // 所属部门
        goodOrder.setDeptId(customer.getDeptId());
        // 发货方
        goodOrder.setShipId(customer.getCustomerId());
        goodOrder.setShipContacts(bo.getShipContacts());
        goodOrder.setShipContactTel(bo.getShipContactTel());
        // 收货方
        goodOrder.setDeliveryId(customer.getCustomerId());
        goodOrder.setDeliveryContacts(bo.getDeliveryContacts());
        goodOrder.setDeliveryContactTel(bo.getDeliveryContactTel());
        // 根据地址获取经纬度
        String[] origin = GaoDeMapUtil.getLngAndLat(bo.getOriginDistractName() + bo.getOriginAddress()).split(",");
        String[] destination = GaoDeMapUtil.getLngAndLat(bo.getDestinationDistractName() + bo.getDestinationAddress()).split(",");
        // 发货地址
        goodOrder.setOriginDistractId(bo.getOriginDistractId());
        goodOrder.setOriginAddress(bo.getOriginAddress());
        goodOrder.setOriginLng(Float.valueOf(origin[0]));
        goodOrder.setOriginLat(Float.valueOf(origin[1]));
        // 收货地址
        goodOrder.setDestinationDistractId(bo.getDestinationDistractId());
        goodOrder.setDestinationAddress(bo.getDestinationAddress());
        goodOrder.setDestinationLng(Float.valueOf(destination[0]));
        goodOrder.setDestinationLat(Float.valueOf(destination[1]));
        // 订单号
        goodOrder.setOrderCode(goodOrderService.genOrderCode(goodOrder.getDeptId()));
        // 创建人、更新人
        goodOrder.setCreateBy("众油平台");
        goodOrder.setCreateTime(DateUtil.date());
        goodOrder.setUpdateBy("众油平台");
        goodOrder.setUpdateTime(DateUtil.date());
        // 新增订单信息
        goodOrderService.save(goodOrder);
        // 订单货物明细
        LogiGoodSource goodSource = getGoodSource(customer.getDeptId(), bo.getGoodsName(), bo.getGoodsType());
        LogiOrderGoodSource logiOrderGoodSource = BeanUtil.copyProperties(goodSource, LogiOrderGoodSource.class, "id");
        logiOrderGoodSource.setGoodOrderId(goodOrder.getGoodOrderId());
        logiOrderGoodSource.setNum(bo.getNum());
        logiOrderGoodSource.setWeight(bo.getWeight());
        logiOrderGoodSource.setBulk(bo.getBulk());
        // 创建人、更新人
        logiOrderGoodSource.setCreateBy("众油平台");
        logiOrderGoodSource.setCreateTime(DateUtil.date());
        logiOrderGoodSource.setUpdateBy("众油平台");
        logiOrderGoodSource.setUpdateTime(DateUtil.date());
        // 新增订单货物明细
        orderGoodSourceService.save(logiOrderGoodSource);
    }

    @Override
    public void cancelOrder(CancelOrderBo bo) {
        LogiGoodOrder goodOrder = getGoodOrderByPickupOrderNo(bo.getPickupOrderNo());
        if (goodOrder.getStatus() == GoodOrderStatusEnum.NORMAL.getCode()) {
            goodOrder.setStatus(GoodOrderStatusEnum.CANCEL.getCode());
            goodOrder.setRemark("众油平台已取消订单，取消原因：" + bo.getReason());
            goodOrderService.updateById(goodOrder);
        }
        // TODO 如果订单已转成运单，且已调度司机，则发送订单取消短信给司机
//        SysSmsBo sysSmsBo = new SysSmsBo();
//        smsService.sendSms(sysSmsBo, SecurityConstants.INNER);
    }

    @Override
    public void confirmSchedule(ConfirmScheduleBo bo) {
        LogiGoodOrder goodOrder = getGoodOrderByPickupOrderNo(bo.getPickupOrderNo());
        if (ObjectUtil.isNotNull(goodOrder.getWaybillId())) {
            LogiWaybill waybill = waybillService.getById(goodOrder.getWaybillId());
            if (ObjectUtil.isNotNull(waybill) && ObjectUtil.isNotNull(waybill.getScheduleNo())) {
                scheduleService.update(Wrappers.lambdaUpdate(LogiSchedule.class)
                        .set(LogiSchedule::getCanDepart, 1)
                        .eq(LogiSchedule::getScheduleNo, waybill.getScheduleNo())
                        .eq(LogiSchedule::getCanDepart, 0));
            }
        }
    }

    @Override
    public void realPickupInfo(RealPickupInfoBo bo) {
        LogiGoodOrder goodOrder = getGoodOrderByPickupOrderNo(bo.getPickupOrderNo());
        List<LogiOrderGoodSource> orderGoodSources = orderGoodSourceService.getByGoodOrderIds(CollUtil.newArrayList(goodOrder.getGoodOrderId()));
        for (LogiOrderGoodSource orderGoodSource : orderGoodSources) {
            if (orderGoodSource.getGoodsName().equals(bo.getGoodsName())) {
                orderGoodSource.setRealWeight(bo.getRealWeight());
                orderGoodSourceService.updateById(orderGoodSource);
            }
        }
    }

    @Override
    public void payInfo(PayInfoBo bo) {
        LogiGoodOrder goodOrder = getGoodOrderByPickupOrderNo(bo.getPickupOrderNo());
        goodOrder.setPayAmount(bo.getPayAmount());
        goodOrder.setPayTime(bo.getPayTime());
        goodOrderService.updateById(goodOrder);
    }

    @Override
    public String getLngAndLatByAddress(String address) {
        return GaoDeMapUtil.getLngAndLat(address);
    }

    /**
     * 根据收发货地获取里程数
     *
     * @author fengxy
     * @date 2024/01/15 16:47
     **/
    public static BigDecimal getMilesByAddress(String originAddress, String destinationAddress) {
        String origin = GaoDeMapUtil.getLngAndLat(originAddress);
        String destination = GaoDeMapUtil.getLngAndLat(destinationAddress);
        String routePlan = GaoDeMapUtil.routePlan(origin, destination);
        JSONObject route = JSONUtil.parseObj(routePlan);
        List<JSONObject> paths = route.getBeanList("paths", JSONObject.class);
        return paths.get(0).getBigDecimal("distance").divide(BigDecimal.valueOf(1000));
    }

    /**
     * 根据提货单号获取订单信息
     *
     * @author fengxy
     * @date 2024/01/15 16:47
     **/
    private LogiGoodOrder getGoodOrderByPickupOrderNo(String pickupOrderNo) {
        LogiGoodOrder goodOrder = goodOrderService.getOne(Wrappers.lambdaQuery(LogiGoodOrder.class)
                .eq(LogiGoodOrder::getPickupOrderNo, pickupOrderNo)
                .eq(LogiGoodOrder::getParentId, 0)
                .eq(LogiGoodOrder::getGoodOrderType, 1));
        if (ObjectUtil.isNull(goodOrder)) {
            throw new ServiceException("订单信息不存在");
        }
        return goodOrder;
    }

    /**
     * 根据客户名称和企业信用代码查询客户信息
     *
     * @author fengxy
     * @date 2024/01/22 21:21
     **/
    private LogiCustomer getCustomer(Long deptId, String customerName, String customerCode) {
        LogiCustomer customer = customerService.getOne(Wrappers.lambdaQuery(LogiCustomer.class)
                .eq(LogiCustomer::getDeptId, deptId)
                .eq(LogiCustomer::getCustomerCode, customerCode)
                .eq(LogiCustomer::getStatus, 0)
                .last("limit 1"));
        if (ObjectUtil.isNull(customer)) {
            customer = new LogiCustomer();
            customer.setDeptId(deptId);
            customer.setCustomerName(customerName);
            customer.setCustomerCode(customerCode);
            customerService.save(customer);
        }
        return customer;
    }

    /**
     * 根据货物名称、货物类型获取货物信息
     *
     * @author fengxy
     * @date 2024/01/19 9:09
     **/
    private LogiGoodSource getGoodSource(Long deptId, String goodsName, Integer goodsType) {
        LogiGoodSource goodSource = goodSourceService.getOne(Wrappers.lambdaQuery(LogiGoodSource.class)
                .eq(LogiGoodSource::getDeptId, deptId)
                .eq(LogiGoodSource::getGoodsName, goodsName)
                .eq(LogiGoodSource::getGoodsType, goodsType)
                .eq(LogiGoodSource::getPackingType, 5)
                .last("limit 1"));
        if (ObjectUtil.isNull(goodSource)) {
            goodSource = new LogiGoodSource();
            goodSource.setDeptId(deptId);
            goodSource.setGoodsName(goodsName);
            goodSource.setGoodsType(goodsType);
            goodSource.setPackingType(5);
            goodSourceService.save(goodSource);
        }
        return goodSource;
    }
}
